home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / russell / gc32.lha / os_dep.c < prev    next >
C/C++ Source or Header  |  1993-07-16  |  22KB  |  823 lines

  1. /*
  2.  * Copyright (c) 1991-1993 by Xerox Corporation.  All rights reserved.
  3.  *
  4.  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  5.  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
  6.  *
  7.  * Permission is hereby granted to copy this garbage collector for any purpose,
  8.  * provided the above notices are retained on all copies.
  9.  */
  10. # include "gc_private.h"
  11. # include <stdio.h>
  12. # include <signal.h>
  13.  
  14. /* Blatantly OS dependent routines, except for those that are related     */
  15. /* dynamic loading.                            */
  16.  
  17. /* Disable and enable signals during nontrivial allocations    */
  18.  
  19. # ifdef OS2
  20.  
  21. # define INCL_DOSEXCEPTIONS
  22. # define INCL_DOSPROCESS
  23. # define INCL_DOSERRORS
  24. # define INCL_DOSMODULEMGR
  25. # include <os2.h>
  26.  
  27. /* A kludge to get around what appears to be a header file bug */
  28. # ifndef WORD
  29. #   define WORD unsigned short
  30. # endif
  31. # ifndef DWORD
  32. #   define DWORD unsigned long
  33. # endif
  34.  
  35. # define EXE386 1
  36. # include <newexe.h>
  37. # include <exe386.h>
  38.  
  39. void GC_disable_signals(void)
  40. {
  41.     ULONG nest;
  42.     
  43.     DosEnterMustComplete(&nest);
  44.     if (nest != 1) ABORT("nested GC_disable_signals");
  45. }
  46.  
  47. void GC_enable_signals(void)
  48. {
  49.     ULONG nest;
  50.     
  51.     DosExitMustComplete(&nest);
  52.     if (nest != 0) ABORT("GC_enable_signals");
  53. }
  54.  
  55.  
  56. # else
  57.  
  58. #  ifndef PCR
  59.  
  60. #   ifdef sigmask
  61.     /* Use the traditional BSD interface */
  62. #    define SIGSET_T int
  63. #    define SIG_DEL(set, signal) (set) &= ~(sigmask(signal))
  64. #    define SIG_FILL(set)  (set) = 0x7fffffff
  65.           /* Setting the leading bit appears to provoke a bug in some    */
  66.           /* longjmp implementations.  Most systems appear not to have    */
  67.           /* a signal 32.                        */
  68. #    define SIGSETMASK(old, new) (old) = sigsetmask(new)
  69. #   else
  70.     /* Use POSIX/SYSV interface    */
  71. #    define SIGSET_T sigset_t
  72. #    define SIG_DEL(set, signal) sigdelset(&(set), (signal))
  73. #    define SIG_FILL(set) sigfillset(&set)
  74. #    define SIGSETMASK(old, new) sigprocmask(SIG_SETMASK, &(new), &(old))
  75. #   endif
  76.  
  77. static bool mask_initialized = FALSE;
  78.  
  79. static SIGSET_T new_mask;
  80.  
  81. static SIGSET_T old_mask;
  82.  
  83. static SIGSET_T dummy;
  84.  
  85. void GC_disable_signals()
  86. {
  87.     if (!mask_initialized) {
  88.         SIG_FILL(new_mask);
  89.  
  90.     SIG_DEL(new_mask, SIGSEGV);
  91.     SIG_DEL(new_mask, SIGILL);
  92.     SIG_DEL(new_mask, SIGQUIT);
  93. #    ifdef SIGBUS
  94.         SIG_DEL(new_mask, SIGBUS);
  95. #    endif
  96. #    ifdef SIGIOT
  97.         SIG_DEL(new_mask, SIGIOT);
  98. #    endif
  99. #    ifdef SIGEMT
  100.         SIG_DEL(new_mask, SIGEMT);
  101. #    endif
  102. #    ifdef SIGTRAP
  103.         SIG_DEL(new_mask, SIGTRAP);
  104. #    endif 
  105.     mask_initialized = TRUE;
  106.     }     
  107.     SIGSETMASK(old_mask,new_mask);
  108. }
  109.  
  110. void GC_enable_signals()
  111. {
  112.     SIGSETMASK(dummy,old_mask);
  113. }
  114.  
  115. #  endif  /* !PCR */
  116.  
  117. # endif /*!OS/2 */
  118.  
  119. /*
  120.  * Find the base of the stack.
  121.  * Used only in single-threaded environment.
  122.  * With threads, GC_mark_roots needs to know how to do this.
  123.  * Called with allocator lock held.
  124.  */
  125.  
  126. # ifdef OS2
  127.  
  128. ptr_t GC_get_stack_base()
  129. {
  130.     PTIB ptib;
  131.     PPIB ppib;
  132.     
  133.     if (DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) {
  134.         GC_err_printf0("DosGetInfoBlocks failed\n");
  135.         ABORT("DosGetInfoBlocks failed\n");
  136.     }
  137.     return((ptr_t)(ptib -> tib_pstacklimit));
  138. }
  139.  
  140. # else
  141.  
  142. # if !defined(THREADS) && !defined(STACKBOTTOM) && defined(HEURISTIC2)
  143.   /* Some tools to implement HEURISTIC2    */
  144. #   define MIN_PAGE_SIZE 256    /* Smallest conceivable page size, bytes */
  145. #   include <setjmp.h>
  146.     /* static */ VOLATILE jmp_buf GC_jmp_buf;
  147.     
  148.     /*ARGSUSED*/
  149.     void GC_fault_handler(sig)
  150.     int sig;
  151.     {
  152.         longjmp(GC_jmp_buf, 1);
  153.     }
  154. # endif
  155.  
  156. ptr_t GC_get_stack_base()
  157. {
  158.     word dummy;
  159.     static VOLATILE ptr_t result;
  160.             /* Needs to be static, since otherwise it may not be    */
  161.             /* preserved across the longjmp.  Can safely be     */
  162.             /* static since it's only called once, with the        */
  163.             /* allocation lock held.                */
  164. #   ifdef __STDC__
  165.     typedef void (*handler)(int);
  166. #   else
  167.     typedef void (*handler)();
  168. #   endif
  169. #   ifdef HEURISTIC2
  170.       static handler old_segv_handler, old_bus_handler;
  171.               /* See above for static declaration.            */
  172. #   endif
  173. #   define STACKBOTTOM_ALIGNMENT_M1 0xffffff
  174.  
  175. #   ifdef STACKBOTTOM
  176.     return(STACKBOTTOM);
  177. #   else
  178. #    ifdef HEURISTIC1
  179. #       ifdef STACK_GROWS_DOWN
  180.          result = (ptr_t)((((word)(&dummy))
  181.                         + STACKBOTTOM_ALIGNMENT_M1)
  182.                   & ~STACKBOTTOM_ALIGNMENT_M1);
  183. #       else
  184.          result = (ptr_t)(((word)(&dummy))
  185.                   & ~STACKBOTTOM_ALIGNMENT_M1);
  186. #       endif
  187. #    endif /* HEURISTIC1 */
  188. #    ifdef HEURISTIC2
  189.        old_segv_handler = signal(SIGSEGV, GC_fault_handler);
  190. #       ifdef SIGBUS
  191.          old_bus_handler = signal(SIGBUS, GC_fault_handler);
  192. #       endif
  193.        if (setjmp(GC_jmp_buf) == 0) {
  194.          result = (ptr_t)(((word)(&dummy))
  195.                   & ~(MIN_PAGE_SIZE-1));
  196.          for (;;) {
  197. #             ifdef STACK_GROWS_DOWN
  198.            result += MIN_PAGE_SIZE;
  199. #             else
  200.            result -= MIN_PAGE_SIZE;
  201. #             endif
  202.          GC_noop(*result);
  203.          }
  204.        }
  205.        (void) signal(SIGSEGV, old_segv_handler);
  206. #       ifdef SIGBUS
  207.            (void) signal(SIGBUS, old_bus_handler);
  208. #       endif
  209. #       ifdef STACK_GROWS_UP
  210.           result += MIN_PAGE_SIZE;
  211. #       endif
  212. #    endif /* HEURISTIC2 */
  213.         return(result);
  214. #   endif /* STACKBOTTOM */
  215. }
  216.  
  217. # endif /* ! OS2 */
  218.  
  219. /*
  220.  * Register static data segment(s) as roots.
  221.  * If more data segments are added later then they need to be registered
  222.  * add that point (as we do with SunOS dynamic loading),
  223.  * or GC_mark_roots needs to check for them (as we do with PCR).
  224.  * Called with allocator lock held.
  225.  */
  226.  
  227. # ifdef OS2
  228.  
  229. void GC_register_data_segments()
  230. {
  231.     PTIB ptib;
  232.     PPIB ppib;
  233.     HMODULE module_handle;
  234. #   define PBUFSIZ 512
  235.     UCHAR path[PBUFSIZ];
  236.     FILE * myexefile;
  237.     struct exe_hdr hdrdos;    /* MSDOS header.    */
  238.     struct e32_exe hdr386;    /* Real header for my executable */
  239.     struct o32_obj seg;    /* Currrent segment */
  240.     int nsegs;
  241.     
  242.     
  243.     if (DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) {
  244.         GC_err_printf0("DosGetInfoBlocks failed\n");
  245.         ABORT("DosGetInfoBlocks failed\n");
  246.     }
  247.     module_handle = ppib -> pib_hmte;
  248.     if (DosQueryModuleName(module_handle, PBUFSIZ, path) != NO_ERROR) {
  249.         GC_err_printf0("DosQueryModuleName failed\n");
  250.         ABORT("DosGetInfoBlocks failed\n");
  251.     }
  252.     myexefile = fopen(path, "rb");
  253.     if (myexefile == 0) {
  254.         GC_err_puts("Couldn't open executable ");
  255.         GC_err_puts(path); GC_err_puts("\n");
  256.         ABORT("Failed to open executable\n");
  257.     }
  258.     if (fread((char *)(&hdrdos), 1, sizeof hdrdos, myexefile) < sizeof hdrdos) {
  259.         GC_err_puts("Couldn't read MSDOS header from ");
  260.         GC_err_puts(path); GC_err_puts("\n");
  261.         ABORT("Couldn't read MSDOS header");
  262.     }
  263.     if (E_MAGIC(hdrdos) != EMAGIC) {
  264.         GC_err_puts("Executable has wrong DOS magic number: ");
  265.         GC_err_puts(path); GC_err_puts("\n");
  266.         ABORT("Bad DOS magic number");
  267.     }
  268.     if (fseek(myexefile, E_LFANEW(hdrdos), SEEK_SET) != 0) {
  269.         GC_err_puts("Seek to new header failed in ");
  270.         GC_err_puts(path); GC_err_puts("\n");
  271.         ABORT("Bad DOS magic number");
  272.     }
  273.     if (fread((char *)(&hdr386), 1, sizeof hdr386, myexefile) < sizeof hdr386) {
  274.         GC_err_puts("Couldn't read MSDOS header from ");
  275.         GC_err_puts(path); GC_err_puts("\n");
  276.         ABORT("Couldn't read OS/2 header");
  277.     }
  278.     if (E32_MAGIC1(hdr386) != E32MAGIC1 || E32_MAGIC2(hdr386) != E32MAGIC2) {
  279.         GC_err_puts("Executable has wrong OS/2 magic number:");
  280.         GC_err_puts(path); GC_err_puts("\n");
  281.         ABORT("Bad OS/2 magic number");
  282.     }
  283.     if ( E32_BORDER(hdr386) != E32LEBO || E32_WORDER(hdr386) != E32LEWO) {
  284.         GC_err_puts("Executable %s has wrong byte order: ");
  285.         GC_err_puts(path); GC_err_puts("\n");
  286.         ABORT("Bad byte order");
  287.     }
  288.     if ( E32_CPU(hdr386) == E32CPU286) {
  289.         GC_err_puts("GC can't handle 80286 executables: ");
  290.         GC_err_puts(path); GC_err_puts("\n");
  291.         EXIT();
  292.     }
  293.     if (fseek(myexefile, E_LFANEW(hdrdos) + E32_OBJTAB(hdr386),
  294.               SEEK_SET) != 0) {
  295.         GC_err_puts("Seek to object table failed: ");
  296.         GC_err_puts(path); GC_err_puts("\n");
  297.         ABORT("Seek to object table failed");
  298.     }
  299.     for (nsegs = E32_OBJCNT(hdr386); nsegs > 0; nsegs--) {
  300.       int flags;
  301.       if (fread((char *)(&seg), 1, sizeof seg, myexefile) < sizeof seg) {
  302.         GC_err_puts("Couldn't read obj table entry from ");
  303.         GC_err_puts(path); GC_err_puts("\n");
  304.         ABORT("Couldn't read obj table entry");
  305.       }
  306.       flags = O32_FLAGS(seg);
  307.       if (!(flags & OBJWRITE)) continue;
  308.       if (!(flags & OBJREAD)) continue;
  309.       if (flags & OBJINVALID) {
  310.           GC_err_printf0("Object with invalid pages?\n");
  311.           continue;
  312.       } 
  313.       GC_add_roots_inner(O32_BASE(seg), O32_BASE(seg)+O32_SIZE(seg));
  314.     }
  315. }
  316.  
  317. # else
  318.  
  319. void GC_register_data_segments()
  320. {
  321.     extern int end;
  322.  
  323. #   ifndef PCR      
  324.       GC_add_roots_inner(DATASTART, (char *)(&end));
  325. #   endif
  326.     /* Dynamic libraries are added at every collection, since they may  */
  327.     /* change.                                */
  328. }
  329.  
  330. # endif  /* ! OS2 */
  331.  
  332. # if !defined(OS2) && !defined(PCR)
  333.  
  334. extern caddr_t sbrk();
  335. # ifdef __STDC__
  336. #   define SBRK_ARG_T size_t
  337. # else
  338. #   define SBRK_ARG_T int
  339. # endif
  340.  
  341. ptr_t GC_unix_get_mem(bytes)
  342. word bytes;
  343. {
  344.     caddr_t cur_brk = sbrk(0);
  345.     caddr_t result;
  346.     SBRK_ARG_T lsbs = (word)cur_brk & (HBLKSIZE-1);
  347.     
  348.     if (lsbs != 0) {
  349.         if(sbrk(HBLKSIZE - lsbs) == (caddr_t)(-1)) return(0);
  350.     }
  351.     result = sbrk((SBRK_ARG_T)bytes);
  352.     if (result == (caddr_t)(-1)) return(0);
  353.     return((ptr_t)result);
  354. }
  355.  
  356. # endif
  357.  
  358. /*
  359.  * Routines for accessing dirty  bits on virtual pages.
  360.  * We plan to eventaually implement four strategies for doing so:
  361.  * DEFAULT_VDB:    A simple dummy implementation that treats every page
  362.  *        as possibly dirty.  This makes incremental collection
  363.  *        useless, but the implementation is still correct.
  364.  * PCR_VDB:    Use PPCRs virtual dirty bit facility.
  365.  * PROC_VDB:    Use the /proc facility for reading dirty bits.  Only
  366.  *        works under some SVR4 variants.  Even then, it may be
  367.  *        too slow to be entirely satisfactory.  Requires reading
  368.  *        dirty bits for entire address space.  Implementations tend
  369.  *        to assume that the client is a (slow) debugger.
  370.  * MPROTECT_VDB:Protect pages and then catch the faults to keep track of
  371.  *        dirtied pages.  The implementation (and implementability)
  372.  *        is highly system dependent.  This usually fails when system
  373.  *        calls write to a protected page.  We prevent the read system
  374.  *        call from doing so.  It is the clients responsibility to
  375.  *        make sure that other system calls are similarly protected
  376.  *        or write only to the stack.
  377.  */
  378.  
  379. # ifdef DEFAULT_VDB
  380.  
  381. /* All of the following assume the allocation lock is held, and    */
  382. /* signals are disabled.                    */
  383.  
  384. /* The client asserts that unallocated pages in the heap are never    */
  385. /* written.                                */
  386.  
  387. /* Initialize virtual dirty bit implementation.            */
  388. void GC_dirty_init()
  389. {
  390. }
  391.  
  392. /* Retrieve system dirty bits for heap to a local buffer.    */
  393. /* Restore the systems notion of which pages are dirty.        */
  394. void GC_read_dirty()
  395. {}
  396.  
  397. /* Is the HBLKSIZE sized page at h marked dirty in the local buffer?    */
  398. /* If the actual page size is different, this returns TRUE if any    */
  399. /* of the pages overlapping h are dirty.  This routine may err on the    */
  400. /* side of labelling pages as dirty (and this implementation does).    */
  401. /*ARGSUSED*/
  402. bool GC_page_was_dirty(h)
  403. struct hblk *h;
  404. {
  405.     return(TRUE);
  406. }
  407.  
  408. /* A call hints that h is about to be written    */
  409. /*ARGSUSED*/
  410. void GC_write_hint(h)
  411. struct hblk *h;
  412. {
  413. }
  414.  
  415. # endif /* DEFAULT_VDB */
  416.  
  417.  
  418. # ifdef MPROTECT_VDB
  419.  
  420. /*
  421.  * See DEFAULT_VDB for interface descriptions.
  422.  */
  423.  
  424. /*
  425.  * This implementation maintains dirty bits itself by catching write
  426.  * faults and keeping track of them.  We assume nobody else catches
  427.  * SIGBUS or SIGSEGV.  We assume no write faults occur in system calls
  428.  * except as a result of a read system call.  This means clients must
  429.  * either ensure that system calls do not touch the heap, or must
  430.  * provide their own wrappers analogous to the one for read.
  431.  * This implementation is currently SunOS 4.X and IRIX 5.X specific, though we
  432.  * tried to use portable code where easily possible.  It is known
  433.  * not to work under a number of other systems.
  434.  */
  435.  
  436. # include <sys/mman.h>
  437. # include <signal.h>
  438. # include <sys/syscall.h>
  439.  
  440. VOLATILE page_hash_table GC_dirty_pages;
  441.                 /* Pages dirtied since last GC_read_dirty. */
  442.  
  443. word GC_page_size;
  444.  
  445. /*ARGSUSED*/
  446. # ifdef SUNOS4
  447.     void GC_write_fault_handler(sig, code, scp, addr)
  448.     int sig, code;
  449.     struct sigcontext *scp;
  450.     char * addr;
  451. #   define SIG_OK (sig == SIGSEGV || sig == SIGBUS)
  452. #   define CODE_OK (FC_CODE(code) == FC_PROT \
  453.                     || (FC_CODE(code) == FC_OBJERR \
  454.                     && FC_ERRNO(code) == FC_PROT))
  455.  
  456. # else
  457. #   if defined(IRIX5) || defined(ALPHA) /* OSF1 */
  458. #     include <errno.h>
  459.       void GC_write_fault_handler(int sig, int code, struct sigcontext *scp)
  460. #     define SIG_OK (sig == SIGSEGV)
  461. #     ifdef ALPHA
  462. #    define SIG_PF void (*)(int)
  463. #       define CODE_OK (code == 2 /* experimentally determined */)
  464. #     else
  465. #       define CODE_OK (code == EACCES)
  466. #     endif
  467. #   endif
  468. # endif
  469. {
  470.     register int i;
  471. #   ifdef IRIX5
  472.     char * addr = (char *) (scp -> sc_badvaddr);
  473. #   endif
  474. #   ifdef ALPHA
  475.     char * addr = (char *) (scp -> sc_traparg_a0);
  476. #   endif
  477.     
  478.     if (SIG_OK && CODE_OK) {
  479.         register struct hblk * h =
  480.                 (struct hblk *)((word)addr & ~(GC_page_size-1));
  481.         
  482.         for (i = 0; i < GC_page_size/HBLKSIZE; i++) {
  483.             register int index = PHT_HASH(h+i);
  484.             
  485.             if (HDR(h+i) == 0) {
  486.                 ABORT("Unexpected bus error or segmentation fault");
  487.             }
  488.             set_pht_entry_from_index(GC_dirty_pages, index);
  489.         }
  490.         if (mprotect((caddr_t)h, (int)GC_page_size,
  491.             PROT_WRITE | PROT_READ | PROT_EXEC) < 0) {
  492.             ABORT("mprotect failed in handler");
  493.         }
  494. #    if defined(IRIX5) || defined(ALPHA)
  495.         /* IRIX resets the signal handler each time. */
  496.         signal(SIGSEGV, (SIG_PF) GC_write_fault_handler);
  497. #    endif
  498.         /* The write may not take place before dirty bits are read.    */
  499.         /* But then we'll fault again ...                */
  500.         return;
  501.     }
  502.  
  503.     ABORT("Unexpected bus error or segmentation fault");
  504. }
  505.  
  506. void GC_write_hint(h)
  507. struct hblk *h;
  508. {
  509.     register struct hblk * h_trunc =
  510.                 (struct hblk *)((word)h & ~(GC_page_size-1));
  511.     register int i;
  512.     register bool found_clean = FALSE;
  513.     
  514.     for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
  515.         register int index = PHT_HASH(h_trunc+i);
  516.             
  517.         if (!get_pht_entry_from_index(GC_dirty_pages, index)) {
  518.             found_clean = TRUE;
  519.             set_pht_entry_from_index(GC_dirty_pages, index);
  520.         }
  521.     }
  522.     if (found_clean) {
  523.        if (mprotect((caddr_t)h_trunc, (int)GC_page_size,
  524.             PROT_WRITE | PROT_READ | PROT_EXEC) < 0) {
  525.             ABORT("mprotect failed in GC_write_hint");
  526.         }
  527.     }
  528. }
  529.                  
  530. void GC_dirty_init()
  531. {
  532.     GC_page_size = getpagesize();
  533.     if (GC_page_size % HBLKSIZE != 0) {
  534.         GC_err_printf0("Page size not multiple of HBLKSIZE\n");
  535.         ABORT("Page size not multiple of HBLKSIZE");
  536.     }
  537. #   ifdef SUNOS4
  538.       if (signal(SIGBUS, GC_write_fault_handler) != SIG_DFL) {
  539.         GC_err_printf0("Clobbered other SIGBUS handler\n");
  540.       }
  541.       if (signal(SIGSEGV, GC_write_fault_handler) != SIG_DFL) {
  542.         GC_err_printf0("Clobbered other SIGSEGV handler\n");
  543.       }
  544. #   endif
  545. #   if defined(IRIX5) || defined(ALPHA)
  546.       if (signal(SIGSEGV, (SIG_PF)GC_write_fault_handler) != SIG_DFL) {
  547.         GC_err_printf0("Clobbered other SIGSEGV handler\n");
  548.       }
  549. #   endif
  550. }
  551.  
  552.  
  553.  
  554. void GC_protect_heap()
  555. {
  556.     word ps = GC_page_size;
  557.     word pmask = (ps-1);
  558.     ptr_t start;
  559.     word offset;
  560.     word len;
  561.     int i;
  562.     
  563.     for (i = 0; i < GC_n_heap_sects; i++) {
  564.         offset = (word)(GC_heap_sects[i].hs_start) & pmask;
  565.         start = GC_heap_sects[i].hs_start - offset;
  566.         len = GC_heap_sects[i].hs_bytes + offset;
  567.         len += ps-1; len &= ~pmask;
  568.         if (mprotect((caddr_t)start, (int)len, PROT_READ | PROT_EXEC) < 0) {
  569.             ABORT("mprotect failed");
  570.         }
  571.     }
  572. }
  573.  
  574. # ifdef THREADS
  575. --> The following is broken.  We can lose dirty bits.  We would need
  576. --> the signal handler to cooperate, as in PCR.
  577. # endif
  578.  
  579. void GC_read_dirty()
  580. {
  581.     bcopy((char *)GC_dirty_pages, (char *)GC_grungy_pages,
  582.           (int)(sizeof GC_dirty_pages));
  583.     bzero((char *)GC_dirty_pages, (int)(sizeof GC_dirty_pages));
  584.     GC_protect_heap();
  585. }
  586.  
  587. bool GC_page_was_dirty(h)
  588. struct hblk * h;
  589. {
  590.     register word index = PHT_HASH(h);
  591.     
  592.     return(HDR(h) == 0 || get_pht_entry_from_index(GC_grungy_pages, index));
  593. }
  594.  
  595. void GC_begin_syscall()
  596. {
  597.     DISABLE_SIGNALS();
  598.     LOCK();
  599. }
  600.  
  601. void GC_end_syscall()
  602. {
  603.     UNLOCK();
  604.     ENABLE_SIGNALS();
  605. }
  606.  
  607. void GC_unprotect_range(addr, len)
  608. ptr_t addr;
  609. word len;
  610. {
  611.     struct hblk * start_block;
  612.     struct hblk * end_block;
  613.     register struct hblk *h;
  614.     ptr_t obj_start;
  615.     
  616.     if (!GC_incremental) return;
  617.     obj_start = GC_base(addr);
  618.     if (obj_start == 0) return;
  619.     if (GC_base(addr + len - 1) != obj_start) {
  620.         ABORT("GC_unprotect_range(range bigger than object)");
  621.     }
  622.     start_block = (struct hblk *)((word)addr & ~(GC_page_size - 1));
  623.     end_block = (struct hblk *)((word)(addr + len - 1) & ~(GC_page_size - 1));
  624.     end_block += GC_page_size/HBLKSIZE - 1;
  625.     for (h = start_block; h <= end_block; h++) {
  626.         register word index = PHT_HASH(h);
  627.         
  628.         set_pht_entry_from_index(GC_dirty_pages, index);
  629.     }
  630.     if (mprotect((caddr_t)start_block,
  631.                  (int)((ptr_t)end_block - (ptr_t)start_block)
  632.                  + HBLKSIZE,
  633.                  PROT_WRITE | PROT_READ | PROT_EXEC) < 0) {
  634.         ABORT("mprotect failed in GC_unprotect_range");
  635.     }
  636. }
  637.  
  638. /* Replacement for UNIX system call.     */
  639. /* Other calls that write to the heap     */
  640. /* should be handled similarly.         */
  641. # ifndef LINT
  642.   int read(fd, buf, nbyte)
  643. # else
  644.   int GC_read(fd, buf, nbyte)
  645. # endif
  646. int fd;
  647. char *buf;
  648. int nbyte;
  649. {
  650.     int result;
  651.     
  652.     GC_begin_syscall();
  653.     GC_unprotect_range(buf, (word)nbyte);
  654.     result = syscall(SYS_read, fd, buf, nbyte);
  655.     GC_end_syscall();
  656.     return(result);
  657. }
  658.  
  659. # endif /* MPROTECT_VDB */
  660.  
  661. # ifdef PROC_VDB
  662.  
  663. /*
  664.  * See DEFAULT_VDB for interface descriptions.
  665.  */
  666.  
  667. /*
  668.  * This implementaion assumes a Solaris 2.X like /proc pseudo-file-system
  669.  * from which we can read page modified bits.  This facility is far from
  670.  * optimal (e.g. we would like to get the info for only some of the
  671.  * address space), but it avoids intercepting system calls.
  672.  */
  673.  
  674. #include <sys/types.h>
  675. #include <sys/signal.h>
  676. #include <sys/fault.h>
  677. #include <sys/syscall.h>
  678. #include <sys/procfs.h>
  679. #include <sys/stat.h>
  680. #include <fcntl.h>
  681.  
  682. #define BUFSZ 20000
  683. char *GC_proc_buf;
  684.  
  685. int GC_proc_fd;
  686.  
  687. void GC_dirty_init()
  688. {
  689.     int fd;
  690.     char buf[20];
  691.  
  692.     sprintf(buf, "/proc/%d", getpid());
  693.     fd = open(buf, O_RDONLY);
  694.     if (fd < 0) {
  695.         ABORT("/proc open failed");
  696.     }
  697.     GC_proc_fd = ioctl(fd, PIOCOPENPD, 0);
  698.     if (GC_proc_fd < 0) {
  699.         ABORT("/proc ioctl failed");
  700.     }
  701.     GC_proc_buf = GC_scratch_alloc(BUFSZ);
  702. }
  703.  
  704. /* Ignore write hints. They don't help us here.    */
  705. /*ARGSUSED*/
  706. void GC_write_hint(h)
  707. struct hblk *h;
  708. {
  709. }
  710.  
  711. void GC_read_dirty()
  712. {
  713.     unsigned long ps, np;
  714.     int nmaps;
  715.     ptr_t vaddr;
  716.     struct prasmap * map;
  717.     char * bufp;
  718.     ptr_t current_addr, limit;
  719.     int i;
  720.  
  721.     bzero((char *)GC_grungy_pages, (int)(sizeof GC_grungy_pages));
  722.     
  723.     bufp = GC_proc_buf;
  724.     if (read(GC_proc_fd, bufp, BUFSZ) <= 0) {
  725.         ABORT("/proc read failed: BUFSZ too small?\n");
  726.     }
  727.     /* Copy dirty bits into GC_grungy_pages */
  728.         nmaps = ((struct prpageheader *)bufp) -> pr_nmap;
  729.     /* printf( "nmaps = %d, PG_REFERENCED = %d, PG_MODIFIED = %d\n",
  730.              nmaps, PG_REFERENCED, PG_MODIFIED); */
  731.     bufp = bufp + sizeof(struct prpageheader);
  732.     for (i = 0; i < nmaps; i++) {
  733.         map = (struct prasmap *)bufp;
  734.         vaddr = (ptr_t)(map -> pr_vaddr);
  735.         ps = map -> pr_pagesize;
  736.         np = map -> pr_npage;
  737.         /* printf("vaddr = 0x%X, ps = 0x%X, np = 0x%X\n", vaddr, ps, np); */
  738.         limit = vaddr + ps * np;
  739.         bufp += sizeof (struct prasmap);
  740.         for (current_addr = vaddr;
  741.              current_addr < limit; current_addr += ps){
  742.             if ((*bufp++) & PG_MODIFIED) {
  743.                 register struct hblk * h = (struct hblk *) current_addr;
  744.                 
  745.                 while ((ptr_t)h < current_addr + ps) {
  746.                     register word index = PHT_HASH(h);
  747.                     
  748.                     set_pht_entry_from_index(GC_grungy_pages, index);
  749.                     h++;
  750.                 }
  751.             }
  752.         }
  753.         bufp += sizeof(long) - 1;
  754.         bufp = (char *)((unsigned long)bufp & ~(sizeof(long)-1));
  755.     }
  756. }
  757.  
  758. bool GC_page_was_dirty(h)
  759. struct hblk *h;
  760. {
  761.     register word index = PHT_HASH(h);
  762.     
  763.     return(get_pht_entry_from_index(GC_grungy_pages, index));
  764. }
  765.  
  766. # endif /* PROC_VDB */
  767.  
  768.  
  769. # ifdef PCR_VDB
  770.  
  771. # include "pcr/vd/vd.h"
  772.  
  773. # define NPAGES (32*1024)    /* 128 MB */
  774.  
  775. PCR_VD_DB  GC_grungy_bits[NPAGES];
  776.  
  777. ptr_t GC_vd_base;    /* Address corresponding to GC_grungy_bits[0]    */
  778.             /* HBLKSIZE aligned.                */
  779.  
  780. void GC_dirty_init()
  781. {
  782.     /* For the time being, we assume the heap generally grows up */
  783.     GC_vd_base = GC_heap_sects[0].hs_start;
  784.     if (GC_vd_base == 0) {
  785.        ABORT("Bad initial heap segment");
  786.     }
  787.     if (PCR_VD_Start(HBLKSIZE, GC_vd_base, NPAGES*HBLKSIZE)
  788.     != PCR_ERes_okay) {
  789.     ABORT("dirty bit initialization failed");
  790.     }
  791. }
  792.  
  793. void GC_read_dirty()
  794. {
  795.     if (PCR_VD_Clear(GC_vd_base, NPAGES, GC_grungy_bits))
  796.         != PCR_ERes_okay) {
  797.     ABORT("dirty bit read failed");
  798.     }
  799. }
  800.  
  801. bool GC_page_was_dirty(h)
  802. struct hblk *h;
  803. {
  804.     if((ptr_t)h < GC_vd_base || (ptr_t)h >= GC_vd_base + NPAGES*HBLKSIZE) {
  805.     return(TRUE);
  806.     }
  807.     return(GC_grungy_bits[h - (struct hblk *)GC_vd_base] & PCR_VD_DB_dirtyBit);
  808. }
  809.  
  810. /*ARGSUSED*/
  811. void GC_write_hint(h)
  812. struct hblk *h;
  813. {
  814.     PCR_VD_WriteProtectDisable(h, HBLKSIZE);
  815.     PCR_VD_WriteProtectEnable(h, HBLKSIZE);
  816. }
  817.  
  818. # endif /* PCR_VDB */
  819.  
  820.  
  821.  
  822.  
  823.